package cn.itsource.user.service.impl;

import cn.itsource.basic.dto.LoginDto;
import cn.itsource.basic.exception.BusinessException;
import cn.itsource.basic.jwt.JwtUtils;
import cn.itsource.basic.jwt.LoginData;
import cn.itsource.basic.jwt.RsaUtils;
import cn.itsource.basic.util.AjaxResult;
import cn.itsource.basic.util.HttpUtil;
import cn.itsource.basic.util.Md5Utils;
import cn.itsource.basic.util.StrUtils;
import cn.itsource.org.mapper.EmployeeMapper;
import cn.itsource.system.domain.Menu;
import cn.itsource.user.constant.WxConstants;
import cn.itsource.user.domain.Logininfo;
import cn.itsource.user.domain.User;
import cn.itsource.user.domain.Wxuser;
import cn.itsource.user.mapper.LogininfoMapper;
import cn.itsource.user.mapper.UserMapper;
import cn.itsource.user.mapper.WxuserMapper;
import cn.itsource.user.service.ILogininfoService;
import cn.itsource.basic.service.impl.BaseServiceImpl;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.security.PrivateKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 业务实现类：
 */
@Service
public class LogininfoServiceImpl extends BaseServiceImpl<Logininfo> implements ILogininfoService {
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTemplate;
    @Autowired
    private WxuserMapper wxuserMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private EmployeeMapper employeeMapper;

    @Override
    public Map<String, Object> findByAccount(LoginDto loginDto) {
        String account = loginDto.getAccount();
        String checkPass = loginDto.getCheckPass();
        Integer type = loginDto.getType();

        if(StringUtils.isEmpty(account)||StringUtils.isEmpty(checkPass)){
            throw new BusinessException("账户或密码不能为空");
        }

        Logininfo logininfo = logininfoMapper.findByAccount(loginDto);
        if(logininfo==null){
            throw new BusinessException("账号或密码错误000");
        }

        String pwd = Md5Utils.encrypByMd5( checkPass+logininfo.getSalt());
        if(!logininfo.getPassword().equals(pwd)){
            throw new BusinessException("账号或密码错误111");
        }

        if(!logininfo.getDisable()){
            throw new BusinessException("该账号已被禁用");
        }

        /*String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);

        Map<String, Object> map = new HashMap<>();
        map.put("token",token);
        logininfo.setSalt(null);
        logininfo.setPassword(null);
        map.put("logininfo",logininfo);*/
        Map<String, Object> map = loginSuccessJwtHandler(logininfo);

        return map;
    }

    @Override
    public AjaxResult wechatLogin(String code) {
        //1.根据code发送第二个请求：httpUtil，返回json格式字符串
        //a.准备第二个请求和参数
        String url = WxConstants.GET_ACK_URL.replace("APPID",WxConstants.APPID).replace("SECRET",WxConstants.SECRET).replace("CODE",code);
        //调用工具类发送请求，返回json格式的字符串
        String jsonStr = HttpUtil.httpGet(url);

        /*{
        "access_token":"ACCESS_TOKEN",
        "expires_in":7200,
        "refresh_token":"REFRESH_TOKEN",
        "openid":"OPENID",
        "scope":"SCOPE",
        "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
        }*/


        //2.使用fastJson进行处理：获取token，openid
        JSONObject obj = JSONObject.parseObject(jsonStr);
        String access_token = obj.getString("access_token");
        String openid = obj.getString("openid");

        //3.根据openid去查询t_wxuser表
        Wxuser wxuser = wxuserMapper.findByOpenid(openid);
        //3.1.查到了=以前扫过码 = 直接免密登陆【不需要在页面中输入用户名和密码就可以登陆】
        //如果通过openid查询到了微信用户对象
        if(wxuser!=null){
            //疑问：user_id可能为null吗？只要有wxuser，就一定会绑定user_id
            User user = userMapper.findById(wxuser.getUserId());
            if(user!=null){ //并且关联的User对象也有值 - 绑定了 - 后续扫码 - 免密登陆
                Logininfo logininfo = logininfoMapper.findById(user.getLogininfoId());

                /*String token = UUID.randomUUID().toString();//36位随机字符串

                redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);

                //封住返回值：Map【token，logininfo】
                Map<String, Object> map = new HashMap<>();
                map.put("token",token);
                logininfo.setSalt(null);
                logininfo.setPassword(null);
                map.put("logininfo",logininfo);*/
                Map<String, Object> map = loginSuccessJwtHandler(logininfo);

                return new AjaxResult().setResultObj(map);
            }
        }

        //3.2.如果没有查到 = 响应给前端token，openid，前端跳转到绑定页面
        return AjaxResult.me().setSuccess(false).setResultObj("?access_token="+access_token+"&openid="+openid);
    }

    @Override
    public AjaxResult wechatBinder(Map<String, String> map) {
        String phone = map.get("phone");
        String verifyCode = map.get("verifyCode");
        String accessToken = map.get("accessToken");
        String openId = map.get("openId");
        System.out.println(accessToken);
        System.out.println(openId);


        //一：校验：空值校验
        if(StringUtils.isEmpty(phone) || StringUtils.isEmpty(verifyCode)){
            throw new BusinessException("信息不能为空!!!");
        }

        //二：校验：手机验证码校验 - 是否过期，是否错误
        //key-value = binder:phone-code:时间戳
        Object phoneCode = redisTemplate.opsForValue().get("binder:" + phone);
        if(phoneCode==null){
            throw new BusinessException("手机验证码过期!!!");
        }
        if(!phoneCode.toString().split(":")[0].equals(verifyCode)){
            throw  new BusinessException("手机验证码错误!!!");
        }

        //三：组装第三个请求的url地址
        String url = WxConstants.GET_USER_URL.replace("ACCESS_TOKEN", accessToken).
                replace("OPENID", openId);
        //四：发送http请求，并返回json格式的字符串
        String jsonStr = HttpUtil.httpGet(url);

        //五：将json格式的字符串转换成json对象，并转换成一个wxuser对象
        Wxuser wxuser = jsonStr2Wxuser(jsonStr);

        //六：根据电话获取【以前注册过但是没有和微信绑定】或新建user对象【logininfo对象添加】，并将User对象添加到数据库
        User user = userMapper.findByPhone(phone);
        if(user==null){//已经这个电话没有被注册过 = 新建
            //先创建user对象
            user = phone2User(phone);
            //再创建logininfo
            Logininfo logininfo = user2Logininfo(user);

            //先保存logininfo对象
            logininfoMapper.add(logininfo);
            user.setLogininfoId(logininfo.getId());
            //再添加user对象
            userMapper.add(user);
        }

        //七：将user_id设置到wxuser对象中，并将wxuser添加到数据库
        wxuser.setUserId(user.getId());
        wxuserMapper.add(wxuser);

        //八：免密登录
        Logininfo logininfoTemp = logininfoMapper.findById(user.getLogininfoId());

        /*String token = UUID.randomUUID().toString();//36位随机字符串
        redisTemplate.opsForValue().set(token,logininfoTemp,30, TimeUnit.MINUTES);

        //封住返回值：Map【token，logininfo】
        Map<String, Object> mapTemp = new HashMap<>();
        mapTemp.put("token",token);
        logininfoTemp.setSalt(null);
        logininfoTemp.setPassword(null);
        mapTemp.put("logininfo",logininfoTemp);*/
        Map<String, Object> mapTemp = loginSuccessJwtHandler(logininfoTemp);
        //响应数据给前端
        return AjaxResult.me().setResultObj(mapTemp);
    }

    //LogininfoServiceImpl实现类中
    private Map<String, Object> loginSuccessJwtHandler(Logininfo logininfo) {
        try {
            Map<String,Object> map = new HashMap<>();
            //细节：如果是管理员才需要加四个数据，如果是用户只需要：登录信息对象，jwt串【1,4】
            //一：想办法获取四个数据
            //1.登录信息对象 - 在参数中
            logininfo.setSalt(null);
            logininfo.setPassword(null);
            map.put("logininfo",logininfo);
            LoginData loginData = new LoginData();
            loginData.setLogininfo(logininfo);
            if(logininfo.getType()==0){//后台管理员
                //2.当前登录人的所有权限的sn集合 - 昨天写过了 - 直接调用方法
                List<String> permissions = employeeMapper.getSns(logininfo.getId());
                map.put("permissions",permissions);
                loginData.setPermissions(permissions);
                //3.当前登录人的所有二级菜单及其它的父级菜单【前端需要】 - 自己写 - 难点1
                List<Menu> menus = employeeMapper.getMenus(logininfo.getId());
                map.put("menus",menus);
                loginData.setMenus(menus);
            }
            //4.将以上三个数据装到LoginData  - 使用工具类进行加密【1 2】 - jwt串
            PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource("auth_rsa.pri").getFile());
            String jwtToken = JwtUtils.generateTokenExpireInMinutes(loginData, privateKey, 30000);//没有做刷新过期时间

            //二：将四个数据装到map进行返回。疑问：jwt串里面不是已经有登录信息，权限和菜单了吗？ - 前端没有做解密
            map.put("token",jwtToken);
            return map;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  null;
    }

    private Logininfo user2Logininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo);
        logininfo.setType(1);
        logininfo.setDisable(true);
        return logininfo;
    }

    private User phone2User(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        String salt = StrUtils.getComplexRandomString(32);
        //给一个随机密码，可以发短信或发邮箱告诉他。也可以不告诉他 - 后面都是用微信app扫码 - 不会涉及到密码
        String randomPwd = StrUtils.getComplexRandomString(6);
        String md5Pwd = Md5Utils.encrypByMd5(randomPwd + salt);
        user.setSalt(salt);
        user.setPassword(md5Pwd);
        return user;
    }

    private Wxuser jsonStr2Wxuser(String jsonStr) {
        JSONObject obj = JSONObject.parseObject(jsonStr);
        Wxuser wxuser = new Wxuser();
        wxuser.setOpenid(obj.getString("openid"));
        wxuser.setNickname(obj.getString("nickname"));
        //现在微信已经将性别
        wxuser.setSex(Integer.parseInt(obj.getString("sex")));
        //地址：country + province + city
        wxuser.setHeadimgurl(obj.getString("headimgurl"));
        wxuser.setUnionid(obj.getString("unionid"));

        return wxuser;
    }
}
